package com.ld.zxw.index;

import java.io.IOException;
import java.io.StringReader;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.document.Document;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.search.TopFieldCollector;
import org.apache.lucene.search.highlight.Fragmenter;
import org.apache.lucene.search.highlight.Highlighter;
import org.apache.lucene.search.highlight.InvalidTokenOffsetsException;
import org.apache.lucene.search.highlight.QueryScorer;
import org.apache.lucene.search.highlight.SimpleFragmenter;
import org.apache.lucene.search.highlight.SimpleHTMLFormatter;
import com.alibaba.fastjson.JSONObject;
import com.ld.zxw.config.Config;
import com.ld.zxw.config.IndexFactory;
import com.ld.zxw.page.Page;
import com.ld.zxw.util.DateUtil;

public class QueryIndex implements IndexFactory{

	private Logger log = Logger.getLogger(QueryIndex.class);

	/**

	 * 

	 * @param config 基础类

	 * @param query 查询对象

	 * @param obj 反射对象

	 * @param num 查询条数

	 * @param sort 排序

	 * @return

	 */
	@Override
	public <T> List<T> findList(Config config,Query query,Class<T> obj,int num,Sort sort) {
		List<T> list = new ArrayList<>();
		try {
			long start_time = DateUtil.getTime();
			IndexSearcher searcher = config.getIndexSearcher();
			TopDocs rs;
			if(sort != null) {
				rs = searcher.search(query,num,sort);
			}else {
				rs = searcher.search(query,num);
			}
			QueryScorer scorer=new QueryScorer(query);  
			DateUtil.timeConsuming("查询内核耗时", start_time);
			start_time = DateUtil.getTime();
			list = dataHandle(searcher, rs.scoreDocs, scorer, config, obj);
			DateUtil.timeConsuming("查询数据整理耗时", start_time);
		} catch (Exception e) {
			log.error("findList-error:",e);
		}
		return list;
	}

	/**

	 * 

	 * @param config 基础类

	 * @param query 查询对象

	 * @param obj 反射对象

	 * @param pageNumber 当前页

	 * @param pageSize 每页条数

	 * @param sort 排序

	 * @return

	 */
	@Override
	public <T> Page<T> findList(Config config,Query query, int pageNumber,
			int pageSize, Class<T> obj,Sort sort) {
		Page<T> page = new Page<>(new ArrayList<>(), pageNumber, pageSize, 0, 0);
		try {
			if(pageNumber == 0) {
				pageNumber = 1;
			}
			int pageNum = (pageNumber-1) * pageSize;
			IndexSearcher searcher = config.getIndexSearcher(); 
			TopFieldCollector create = TopFieldCollector.create(sort, pageNum+pageSize, false, false, false);
			searcher.search(query,create);
			int totalHits = create.getTotalHits();
			ScoreDoc[] scoreDocs = create.topDocs(pageNum,pageSize).scoreDocs;
			QueryScorer scorer = new QueryScorer(query);
			List<T> dataHandle = dataHandle(searcher, scoreDocs, scorer, config, obj);
			int totalPage = (int) (totalHits / pageSize);
			if (totalHits % pageSize != 0) {
				totalPage++;
			}
			page = new Page<T>(dataHandle, pageNumber, pageSize, totalPage, totalHits);
		}catch (Exception e) {
			log.error("findList-error:",e);
		}
		return page;
	}

	/**

	 * 数据处理

	 * @param query

	 * @param ireader

	 * @param searcher

	 * @param rs

	 * @param scorer

	 * @param config

	 * @param obj

	 * @return

	 * @throws IOException

	 */
	public <T> List<T> dataHandle(IndexSearcher searcher,ScoreDoc[] scoreDocs,QueryScorer scorer,Config config,Class<T> obj) throws IOException{
		List<T> list = new ArrayList<>();
		int length = scoreDocs.length;

		Highlighter highlighter = null;
		List<String> highlighterFields = null;
		if(config.isHighlight()) {
			//创建 高亮对象 获取需要高亮的字段

			highlighter = getHighlighter(config, scorer);
			highlighterFields = config.getHighlightFields();
		}
		for (int i = 0; i < length; i++) {
			JSONObject object = new JSONObject();
			Document doc = searcher.doc(scoreDocs[i].doc);
			//遍历所有字段

			Field[] fields = obj.getDeclaredFields();
			for (int j = 0; j < fields.length; j++) {
				String name = fields[j].getName();
				String value = doc.get(name);
				boolean flag = true;
				//需要高亮

				if(config.isHighlight()) {
					//判断该字段是否需要高亮

					if(highlighterFields.contains(name)) {
						object.put(name, setHighlighter(highlighter, config, name, value));
						flag = false;
					}
				}
				if(flag) {
					object.put(name, value);
				}
			}
			list.add(object.toJavaObject(obj));
		}
		return list;
	}

	public String setHighlighter(Highlighter highlighter,Config config,String name,String value) {
		String v = null;
		if(StringUtils.isNotBlank(name) && StringUtils.isNotBlank(value)) {
			String bestFragment = null;
			try {
				TokenStream tokenStream = config.getAnalyzer().tokenStream(name, new StringReader(value));
				bestFragment = highlighter.getBestFragment(tokenStream,value);
			} catch (IOException | InvalidTokenOffsetsException e) {
				e.printStackTrace();
			}
			if(StringUtils.isNotBlank(bestFragment)) {
				v = bestFragment;
			}
		}else {
			v=value;
		}
		return v;
	}


	public Highlighter getHighlighter(Config config,QueryScorer scorer){
		Fragmenter fragmenter = new SimpleFragmenter(100);//默认字符为100  

		String[] highlight_conf = config.getHighlightConf();
		SimpleHTMLFormatter formatter = new SimpleHTMLFormatter(highlight_conf[0],highlight_conf[1]);
		Highlighter highlighter = new Highlighter(formatter,scorer);
		highlighter.setTextFragmenter(fragmenter);
		return highlighter;
	}
}
